
#include "precompiled.h"
#include "declarativeextension.h"
#include <extensions/context.h>
#include <extensions/application.h>

#include <QtDeclarative>

#include "script/contextimpl.h"
#include "tasks/declarativetask.h"

#include <extensions/application.h>

#include "engine.h"
#include "helper.h"
#include "windowsmanager.h"

#include "windowsmanager.h"
#include "script/declarativeenvironmentex.h"
#include <scripting/system/io/file.h>

class DeclarativeExtensionPrivate{
public:
	DeclarativeExtensionPrivate():
		denvironment(0){}

	~DeclarativeExtensionPrivate() {delete denvironment;}
	QFileInfo fileInfo;	
	DeclarativeEnvironmentEx* denvironment;
	Optra::Extensions::Context* ctx;
	Optra::Extensions::Plugin::Type type;
	QDeclarativeItem* mainItem()
	{
		Optra::Extensions::Application* app = mainApp();
		if (app == 0)
			return 0;

		return app->mainItem();

	}

	Optra::Extensions::Application* mainApp()
	{
//		QDeclarativeItem* item = denvironment->declarativeItem();
//		if (item == 0)
//			return 0;

		QDeclarativeComponent* component = denvironment->component();
		if (component == 0)
			return 0;

		if (denvironment->object() == 0){
			return 0;
		}

		LI.Trace() << denvironment->object()->metaObject()->className();
		//Optra::Extensions::Application* app = qobject_cast<Optra::Extensions::Application*>(denvironment->object());
		Optra::Extensions::Application* app = dynamic_cast<Optra::Extensions::Application*>(denvironment->object());
		if (app == 0)
			return 0;

		LI.Trace() << app->name();
		return app;
	}
};

DeclarativeExtension::DeclarativeExtension(Optra::Extensions::Plugin::Type type, Optra::Extensions::Context* ctx, const QFileInfo& info, Opl::Core::EntityObject *parent) :
		Optra::Extensions::Plugin(type, ctx, parent), O_PRIVATE_CREATE(DeclarativeExtension)
{

	O_D(DeclarativeExtension);

	LI.Trace() << "Create Declarative Extension:";
	LI.Trace() << ctx->toString();
	d->ctx = ctx;
	d->fileInfo = info;
	d->type = type;
	d->denvironment = new DeclarativeEnvironmentEx;

}



DeclarativeEnvironmentEx& DeclarativeExtension::environment()const
{
	O_C(DeclarativeExtension);
	return *d->denvironment;
}

void DeclarativeExtension::registerObject(const QString& name, Opl::Core::EntityObject* object, const QString& package/* = ""*/)
{
	O_D(DeclarativeExtension);
	d->denvironment->registerObject(name, object, package);
}

bool DeclarativeExtension::initialize()
{
	O_D(DeclarativeExtension);
	d->denvironment->initialize(QUrl::fromLocalFile(d->fileInfo.absoluteFilePath()), false);

	switch(d->type)
	{
	case Optra::Extensions::Plugin::extension:
		d->denvironment->registerObject("extension", this);
		break;
	case Optra::Extensions::Plugin::application:
		d->denvironment->registerObject("application",this);
		break;
	}

	d->denvironment->registerObject("context", d->ctx);
	QObject * object = d->denvironment->exec();
	if (object == 0){
		setValid(false);
		LI.Error() << "Unable to exec declarative extension file:" << d->denvironment->errorString();
		setErrorString(d->denvironment->errorString());
		return false;
	}

	setName(object->property("name").toString());

	//connect(this, SIGNAL(Start(Optra::Extensions::Context*)), object, SLOT(Start(Context*)));

	setValid(d->mainApp() != 0);

	if (!valid()){
		LI.Error() << "DeclarativeExtension::initialize:: Invalid Plugin:" << d->fileInfo.absoluteFilePath();
		return false;
	}
	LI.Info() << "Add Declarative item to scene";
	QDeclarativeItem* mainwin = d->mainItem();
	if (mainwin == 0){
		LI.Error() << "invalid mainItem";
		return false;
	}

	Engine::instance()->windowsManager()->addItem(mainwin);
	return true;
}

void DeclarativeExtension::start()
{
	O_D(DeclarativeExtension);	

	QVariant returnedValue;
	LI.Debug() << "Invoking onStart method";
	QMetaObject::invokeMethod(d->denvironment->object(), "onStart", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, QVariant()));
	LI.Info() << "Application onStart returned: " << returnedValue.toString();
	Engine::instance()->windowsManager()->addItem(d->mainItem());
}

bool DeclarativeExtension::registerClass(Opl::Scripting::System::IO::File* file)
{
	Q_ASSERT(file);
	LI.Info() << "Registering class, from QML:" << file->name();

	QString fn = context()->rootDir().absoluteFilePath(file->name());	
	QFileInfo fi(fn);	
	Engine::instance()->windowsManager()->registerQMLControl(fi.baseName(), fn);
	return false;
}


DeclarativeExtension::~DeclarativeExtension()
{
	O_D(DeclarativeExtension);	
	stop();
	O_PRIVATE_DELETE;	
}

void DeclarativeExtension::stop()
{
	O_D(DeclarativeExtension);
	LI.Info() << "Remove Declarative item";
	QDeclarativeItem* mainwin = d->mainItem();
	if (mainwin != 0)
	{
		//mainwin->hide();
		Engine::instance()->windowsManager()->removeItem(mainwin);
	}

	d->denvironment->stop();
}

void DeclarativeExtension::reload()
{
	O_D(DeclarativeExtension);
	stop();	
	d->denvironment->reload();
	start();
}
